# -*- coding: utf-8 -*-
"""
Created on 2010-8-7

@author: morningbzy
"""
from sgs.common.sgs_condition import SGSCondition
from game import Game
from sgs.figure.figure_list import figureList
from sgs.card.card_list import cardList
from sgs.common.constants import roleType
import random

class SGSGame(Game):
    def __init__(self):
        super(SGSGame, self).__init__()
        self.cardList = cardList
        self.figureList = figureList
        self.cmd2Handler = {'JOIN': self.doJoin_,
                            'READY': self.doReady_,
                            'START': self.doStart_}

    def run(self):
        Game.setStatus(self, Game.STARTED)
        cond = SGSCondition()
        self.prepairGame_(cond)
        winners = self.checkWinner()
        lastRoundStarter = -1
        while not winners:
            roundList = self.users.getRoundDeskList(lastRoundStarter)
            lastRoundStarter = roundList[0]
            for desk in roundList:
                user = self.users.getUser(desk)
                if not user.alive:
                    continue
                user.callGameAction('roundBegin', cond)
                user.callGameAction('judgeBegin', cond)
                user.callGameAction('fetchBegin', cond)
                user.callGameAction('actionBegin', cond)
                user.callGameAction('throwBegin', cond)
                user.callGameAction('roundEnd', cond)
            winners = self.checkWinner()
        winnerIds = []
        for winner in winners:
            w = self.users.getUser(winner)
            w.addCmd('YOU_WIN')
            winnerIds = w.id
        self.users.broadcastCmd('YOU_LOSE', winners, winnerIds)

    def checkWinner(self):
        allAlives = self.users.getAlivePlayers()
        isZGAlive, isFZAlive, isNJAlive = [False] * 3
        for player in allAlives:
            role = player.role
            if role == roleType.ZG:
                isZGAlive = True
            elif role == roleType.FZ:
                isFZAlive = True
            elif role == roleType.NJ:
                isNJAlive = True
        assert isZGAlive or isFZAlive or isNJAlive, 'Must one role survive'
        rtn = []
        if isZGAlive:
            if not isFZAlive and not isNJAlive:
                rtn = self.users.role2Desks[roleType.ZG]
                rtn.extend(self.users.role2Desks[roleType.ZC])
        else:
            if isFZAlive and not isNJAlive:
                rtn = self.users.role2Desks[roleType.FZ]
            elif not isFZAlive and isNJAlive:
                rtn = self.users.role2Desks[roleType.NJ]
        return rtn

    def broadcastCmd(self, cmd, args, exceptUId):
        self.users.broadcastCmd(cmd, args, exceptUId)

    def reqSomeoneCard(self, cond, cardType, requier, fromUserDesk, num=1,
                       msg=''):
        rtn = {}
        roundList = self.users.getRoundDeskList(fromUserDesk)
        assert roundList[-1] == fromUserDesk, 'Should end with last starter'
        for desk in roundList[0:-1]:
            user = self.users.getUser(desk)
            card = user.requireCard(cond,
                    condition={'class': cardType}, msg=msg)
            if card:
                rtn[user] = card
                if len(rtn) == num:
                    break
        return rtn

    def cmdNotify(self, cmd, args):
        rtn_cmd, rtn_args = 'DUMMY', []
        handler = self.cmd2Handler.get(cmd, None)
        if handler:
            rtn_cmd, rtn_args = handler(args)
        elif not game.eventStack:
            rtn_cmd = 'BROKE_RULE'
            rtn_args = ['现在谁都不许乱动']
        else:
            cond = self.eventStack[0]
            cond.acquire()
            if cond.notify(args[0], cmd):
                self.eventStack.pop()
                self.respStack.append({'cmd': cmd, 'args': args})
            else:
                rtn_cmd = 'BROKE_RULE'
                rtn_args = ['现在等玩家[%d]的命令:%s' % (cond.deskId, cond.cmds)]
            cond.release()
        return rtn_cmd, rtn_args

    def doReady_(self, args):
        deskId = int(args[0])
        user = self.users.getUser(deskId)
        user.setState(100)
        self.users.broadcastCmd('ACK_READY_B', [deskId], user.id)
        rtn_cmd = 'ACK_READY'
        rtn_args = []
        return rtn_cmd, rtn_args

    def doJoin_(self, args):
        if self.status != Game.PREPARING:
            rtn_cmd = 'GAME_STARTED'
            rtn_args = []
        elif self.users.playerNum == 8: # maximum 8
            rtn_cmd = 'SEAT_FULL'
            rtn_args = []
        else:
            name = args[0]
            deskId = self.users.playerNum
            u_id = self.users.genId()
            newUser = self.users.newUser(u_id, name)
            self.users.add(newUser)
            self.users.broadcastCmd('ACK_JOIN_B', [deskId, name], u_id)
            rtn_cmd = 'ACK_JOIN'
            rtn_args = [deskId, u_id, name]
            for i in range(deskId):
                user = self.users.getUser(i)
                rtn_args.extend([i, user.name, '1' if user.state == 100 else '2'])
        return rtn_cmd, rtn_args

    def doStart_(self, args):
        self.users.broadcastCmd('ACK_START', [])
        self.start()
        rtn_cmd = 'DUMMY'
        rtn_args = []
        return rtn_cmd, rtn_args

    def prepairGame_(self, cond):
        cond.acquire()
        self.assignRole_()
        while not self.users.checkAllFigured():
            self.eventStack.append(cond)
            cond.wait(None, None)
            resp = self.respStack.pop()
            cmd, args = resp['cmd'], resp['args']
            if cmd == 'SET_ZG_FIG':
                self.doSetZGFig_(args)
            elif cmd == 'SET_FIG':
                self.doSetOtherFig_(args)
            else:
                print 'unexpected cmd', cmd
                exit()
        #if all have chosen their figure, tell each user about others' 
        #(except ZG because ZG's already known to all) figure
        allUsers = self.users.getAllPlayers()
        for user1 in allUsers:
            ackArgs = []
            for user2 in allUsers:
                if user2.role != roleType.ZG and user1 != user2:
                    ackArgs.extend([user2.deskId, user2.figures[0].toArray()])
            user1.addCmd('SHOW_OTHERS_FIGURE', ackArgs)
            user1.addCards(cardList.popCards(4))

    def assignRole_(self):
        allUsers = self.users.getAllPlayers()
        roles = [roleType.ZG, roleType.FZ, roleType.ZC, roleType.NJ]
        nUser = len(allUsers)
        if nUser <= 4: roles = roles[0:nUser]
        elif nUser == 5: roles.append(roleType.FZ)
        elif nUser == 6: roles.extend([roleType.NJ, roleType.FZ])
        elif nUser == 7: roles.extend([roleType.ZC, roleType.FZ, roleType.FZ])
        elif nUser == 8: roles.extend([roleType.ZC, roleType.FZ, roleType.FZ, roleType.NJ])
        random.shuffle(roles)
        zgDeskId = -1
        for i in range(len(allUsers)):
            user = allUsers[i]
            role = roles[i]
            user.role = role
            self.users.setDeskRole(user.deskId, role)
            if role == roleType.ZG: #assign 5 candidate figures for ZG
                zgDeskId = user.deskId
                figForZG = figureList.getCandiFiguresForZhugong()
                user.addCmd('ASSIGN_ROLE', [roleType.ZG]+figForZG)
            else:
                user.addCmd('ASSIGN_ROLE', [role])
        # tell everyone who is ZG
        for user in allUsers:
            if user.deskId != zgDeskId:
                user.addCmd('SHOW_OTHERS_ROLE', [zgDeskId, roleType.ZG])

    def doSetZGFig_(self, args):
        deskId = int(args[0])
        figId = int(args[1])
        user = self.users.getUser(deskId)
        user.setFigure(None, figureList.getFigure(figId))
        # Assign candidate figures for other non-ZG players
        allPlayers = self.users.getAllPlayers()
        allPlayers.remove(user)
        figs = figureList.getCandiFiguresForOthers(figId, len(allPlayers))
        for i in range(len(allPlayers)):
            user_ = allPlayers[i]
            figArgs = figs[i*6:(i*6+6)]
            # let others know the figure chosen by ZG 
            user_.addCmd('SHOW_OTHERS_FIGURE', [deskId, user.figures[0].toArray()])
            user_.addCmd('ASSIGN_FIGURE', [user_.deskId] + figArgs)
        user.addCmd('ACK_SET_FIG', user.figures[0].toArray())

    def doSetOtherFig_(self, args):
        deskId = int(args[0])
        figId = int(args[1])
        user = self.users.getUser(deskId)
        user.setFigure(None, figureList.getFigure(figId))
        user.addCmd('ACK_SET_FIG', user.figures[0].toArray())

    def getUser(self, deskId):
        return self.users.getUser(deskId)

    def dispatchCards(self, deskId, num):
        user = self.getUser(deskId)
        cards = self.cardList.popCards(num)
        user.addCards(cards)

    def getAlivePlayers(self):
        return self.users.getAlivePlayers()

game = SGSGame()
